package main

import (
	"bytes"
	"flag"
	"fmt"
	"gitee.com/blueskyxi2006/sql-metrics/dao"
	"gitee.com/blueskyxi2006/sql-metrics/logger"
	models "gitee.com/blueskyxi2006/sql-metrics/model"
	"gopkg.in/ini.v1"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"syscall"
	"text/template"
	"time"
)

func main() {
	var _confPath string
	flag.StringVar(&_confPath, "conf", "conf/app.ini", "配置路径")
	flag.Parse()
	// ----//---------------
	cfg, err := ini.Load(_confPath)
	loglevel := cfg.Section("").Key("log_level").String()
	logFile := cfg.Section("").Key("log_file").String()

	logger.Initial(loglevel,logFile)
	if err != nil {
		logger.Error("Fail to read file: ", _confPath)
		panic("Fail to read file: " + _confPath)
	}
	logger.Debug("App Name:", cfg.Section("").Key("app_name").String())
	logger.Debug("Log Level:", loglevel)
	logger.Debug("IP:", cfg.Section("database").Key("ip").String())
	serverSql := cfg.Section("scripts").Key("server_sql").String()
	groupSql := cfg.Section("scripts").Key("group_sql").String()
	enable := cfg.Section("pushGateway").Key("enable").String()
	url := cfg.Section("pushGateway").Key("url").String()


	logger.Debug("server_sql:", serverSql)
	logger.Debug("group_sql:", groupSql)
	// go func(){}()
	intervalTime := cfg.Section("").Key("intervalTime").String()
	logger.Debug("interval time:", intervalTime)

	// 创建数据库
	// 连接数据库
	err = dao.InitMySQL(cfg)
	if err != nil {
		fmt.Printf("init mysql failed, err:%v\n", err)
		return
	}
	defer dao.Close() // 程序退出关闭数据库连接
	// 模型绑定
	//dao.DB.AutoMigrate(&models.ServerMetrics{})
	//dao.DB.AutoMigrate(&models.GroupMetrics{})

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	_time, _ := strconv.Atoi(intervalTime)
	tickAction(quit, _time,serverSql,groupSql,enable,url)
	logger.Info("Shutdown Server..")

}

func tickAction(stop chan os.Signal, val int,serverSql,groupSql,enable,url string) {
	ticker := time.Tick(time.Duration(time.Second * time.Duration(val)))
BREAK1:
	for i := range ticker {
		select {
		case _ = <-stop:
			logger.Info("-------stop--------")
			break BREAK1
		default:
			fmt.Println(i) //每秒都会执行的任务
			ctx := buildMetrics(serverSql,groupSql)
			fmt.Println(ctx)
			if enable == "false"{
				fmt.Println("enable is false")
				WriteStringToFile("./metrics.txt",ctx)
			}else{
				fmt.Println("enable is true")
				DoBytesPost(url,[]byte(ctx))
			}
			time.Sleep(time.Second * 10)
			//execCMD()
		}
	}
	logger.Info("------loop out------")
}

func execCMD() {
	//c := exec.Command("cmd", "/C", "mysql -uroot -p654321 -h127.0.0.1 -P3306 db_cow < d:/db_cow.sql")
	//首先生成cmd结构体,该结构体包含了很多信息，如执行命令的参数，命令的标准输入输出等
	command := exec.Command("curl", "www.baidu.com")
	//给标准输入以及标准错误初始化一个buffer，每条命令的输出位置可能是不一样的，
	//比如有的命令会将输出放到stdout，有的放到stderr
	command.Stdout = &bytes.Buffer{}
	command.Stderr = &bytes.Buffer{}
	//执行命令，直到命令结束
	err := command.Run()
	if err != nil {
		//打印程序中的错误以及命令行标准错误中的输出
		fmt.Println(err)
		fmt.Println(command.Stderr.(*bytes.Buffer).String())
		return
	}
	//打印命令行的标准输出
	fmt.Println(command.Stdout.(*bytes.Buffer).String())
}

func buildMetrics(serverSql,groupSql string) string{
	sMetrics := models.GetAllServerMetrics(serverSql)
	var stringBuilder bytes.Buffer

	for i, metric := range sMetrics {
		fmt.Println(i,metric)
		str := transPMetricsOut(metric)
		stringBuilder.WriteString(str)
		stringBuilder.WriteString("\n")
		//fmt.Println(str)
	}
	gMetrics := models.GetAllGroupMetrics(groupSql)
	for i, metric := range gMetrics {
		fmt.Println(i,metric)
		str := transGMetricsOut(metric)
		stringBuilder.WriteString(str)
		stringBuilder.WriteString("\n")
		//fmt.Println(str)
	}
	ctx := stringBuilder.String()
	return ctx
}

func transPMetricsOut(sm *models.ServerMetrics) string {
	//file := funcName("./test/tpl/expimp.tpl")

	tmpl, err := template.ParseFiles("./conf/s_metrics.tpl")
	if err != nil {
		panic(err)
	}
	buffer := bytes.Buffer{}
	err = tmpl.Execute(&buffer, sm)
	if err != nil {
		panic(err)
	}

	return buffer.String()
}

func transGMetricsOut(sm *models.GroupMetrics) string {
	//file := funcName("./test/tpl/expimp.tpl")

	tmpl, err := template.ParseFiles("./conf/g_metrics.tpl")
	if err != nil {
		panic(err)
	}
	buffer := bytes.Buffer{}
	err = tmpl.Execute(&buffer, sm)
	if err != nil {
		panic(err)
	}

	return buffer.String()
}

//body提交二进制数据
func DoBytesPost(url string, data []byte) ([]byte, error) {

	body := bytes.NewReader(data)
	request, err := http.NewRequest(http.MethodPost, url, body)
	if err != nil {
		log.Printf("http.NewRequest,[err=%s][url=%s]\n", err, url)
		return []byte(""), err
	}
	request.Header.Set("Connection", "Keep-Alive")
	var resp *http.Response
	resp, err = http.DefaultClient.Do(request)
	if err != nil {
		log.Printf("http.Do failed,[err=%s][url=%s]\n", err, url)
		return []byte(""), err
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("http.Do failed,[err=%s][url=%s]\n", err, url)
	}
	return b, err
}

func WriteStringToFile(fileName string, writeInfo string) {
	_ = IfNoFileToCreate(fileName)
	info := []byte(writeInfo)
	if err := ioutil.WriteFile(fileName, info, 0666); err != nil {
		log.Printf("WriteStringToFileMethod1 写入文件失败:%+v", err)
		return
	}
	log.Printf("WriteStringToFileMethod1 写入文件成功")
}
// IsExists 判断所给路径文件/文件夹是否存在
func IsExists(path string) bool {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil && !os.IsExist(err) {
		return false
	}
	return true
}

// IfNoFileToCreate 文件不存在就创建文件
func IfNoFileToCreate(fileName string) (file *os.File) {
	var f *os.File
	var err error
	if !IsExists(fileName) {
		f, err = os.Create(fileName)
		if err != nil {
			return
		}
		log.Printf("IfNoFileToCreate 函数成功创建文件:%s", fileName)
		defer f.Close()
	}
	return f
}